use std::collections::HashMap;
use std::fs;
use std::path::Path;

use clap::{ArgMatches, Command};
use reqwest::{blocking, StatusCode};
use serde::{Deserialize, Serialize};

use crate::runtime::runtime::{github, os, path, version};

pub(super) const NAME: &'static str = "upd";

pub(super) fn new() -> Command {
    let command = Command::new(NAME).about("更新本地索引");

    command
}

#[derive(Debug, Serialize, Deserialize)]
struct Indexes {
    index: HashMap<String, HashMap<String, Vec<String>>>,
}

pub(super) fn action(_args: &ArgMatches) {
    let manifest = github::MANIFEST.replace("{VERSION}", version::VERSION_NAME);

    let response = blocking::get(manifest);
    if response.is_err() {
        println!("请求索引清单失败: {}", response.unwrap_err());

        return;
    }

    let response = response.unwrap();

    if StatusCode::OK != response.status() {
        println!("请求索引清单失败，错误码: {}", response.status());

        return;
    }

    let indexes: Indexes = serde_yaml::from_str(response.text().unwrap().as_str()).unwrap();
    if indexes.index.get(os::OS).is_none() {
        println!("未支持的系统类型");

        return;
    }

    let index = indexes.index.get(os::OS).unwrap();
    if index.get(os::ARCH).is_none() {
        println!("未支持的系统架构");

        return;
    }

    let index = index.get(os::ARCH).unwrap();
    for name in index.iter() {
        let remote = github::INDEX.replace("{VERSION}", version::VERSION_NAME).replace("{OS}", os::OS).replace("{ARCH}", os::ARCH).replace("{NAME}", name);

        let response = blocking::get(remote.as_str());
        if response.is_err() {
            println!("请求索引失败: {}", response.unwrap_err());

            continue;
        }

        let response = response.unwrap();
        if StatusCode::NOT_FOUND == response.status() {
            continue;
        }

        if StatusCode::OK != response.status() {
            println!("请求索引失败，错误码: {}", response.status());

            continue;
        }

        let local = Path::new(path::DEM_INDEX_PATH).join(name);

        println!("更新索引文件: {} -> {}", remote.as_str(), local.to_str().unwrap());
        let result = fs::write(local, response.text().unwrap());
        if result.is_err() {
            println!("写入本地索引失败: {}", result.unwrap_err());
        }
    }
}